package top.xizai.anti.replay.base.aspect;

import cn.hutool.core.util.CharsetUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.asymmetric.KeyType;
import cn.hutool.crypto.asymmetric.RSA;
import com.example.common.utils.R;
import lombok.extern.log4j.Log4j2;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import top.xizai.anti.replay.base.req.BaseRequest;
import top.xizai.anti.replay.utils.SignUtil;

import javax.servlet.http.HttpServletRequest;

/**
 * @NAME: WSC
 * @DATE: 2021/12/17
 * @DESCRIBE:  防止API接口重放攻击
 **/
@Log4j2
@Aspect
@Component
public class RequestAspect {
    @Autowired
    SignUtil signUtil;

    @Value("${anti-replay.private-key}")
    private String privateKey;

    @Pointcut("execution(* top.xizai.anti.replay.controller.*.*(..))")
    public void pointcut(){}

    @Around("pointcut()")
    public Object validateAndConversionBaseRequest(ProceedingJoinPoint joinPoint) throws Throwable {
        MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
        var parameterTypes = methodSignature.getParameterTypes();

        var attributes = RequestContextHolder.getRequestAttributes();
        var request = (HttpServletRequest) attributes.resolveReference(RequestAttributes.REFERENCE_REQUEST);

        var args = joinPoint.getArgs();

        if ("post".equalsIgnoreCase(request.getMethod())) {
            for (int i = 0; i < parameterTypes.length; i++) {
                var parameterType = parameterTypes[i];
                if (parameterType == BaseRequest.class) {
                    BaseRequest baseRequests = (BaseRequest)args[i];

                    /**
                     * 解密data
                     */
                    var encodeData = baseRequests.getOrDefault("data", "") + "";
                    if (StringUtils.isNotBlank(encodeData)) {
                        var rsa = new RSA(privateKey, null);
                        var decodeData = StrUtil.str(rsa.decrypt(encodeData, KeyType.PrivateKey), CharsetUtil.CHARSET_UTF_8);
                        baseRequests.put("data", decodeData);
                    }

                    try {
                        signUtil.validateSign(baseRequests);
                    }catch (RuntimeException e) {
                        return R.error(e.getMessage());
                    }
                }
            }
        }
        return joinPoint.proceed();
    }
}
